package com.zjl.redis.第16章_分布式锁;

import com.zjl.redis.第06章_SpringBoot整合redis.B2_JedisPool;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ClassName: B_手写分布式锁
 * Package: com.zjl.redis.第16章_分布式锁
 * Description:
 *
 * @Author 张蛟龙
 * @Create 2024/7/8 18:51
 * @Version 1.0
 */
public class B1_手写分布式锁错误版本 {
    private static String AMT = "amt";
    @Test
    public void 模拟归0(){
        //连接 redis
        Jedis redis1 = B2_JedisPool.getRedisPool();
        System.out.println(redis1.get(AMT));
        redis1.set(AMT,"100");
    }
    @Test//没保证  分布式安全
    public void 模拟分布式加普通锁() throws InterruptedException {
        for (int k = 0; k < 2; k++) {
            new Thread(()-> {
                try {
                    B1_手写分布式锁错误版本 b = new B1_手写分布式锁错误版本();//模拟两个程序抢占
                    b.模拟分布式扣减库存();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();

        }
        while (Thread.activeCount()>2){//Thread.activeCount() 返回线程总数
            TimeUnit.MICROSECONDS.sleep(50);
        }
        Jedis redis1 = B2_JedisPool.getRedisPool();
        System.out.println("-------------模拟分布式加普通锁模拟------------------------------");
        System.out.println(redis1.get(AMT));
        redis1.close();
    }

    @Test //没保证 分布式安全  一般不让运行两次 可以  idea中
    // 鼠标右键-> Modify Run Configuration -> Modify options -> Allow multiple instances  打上对号即可
    public void 模拟分布式加普通锁运行两次() throws InterruptedException {
        //连接 redis
        Jedis redis1 = B2_JedisPool.getRedisPool();
        System.out.println(redis1.get(AMT));
        redis1.set(AMT,"100");

        B1_手写分布式锁错误版本 b = new B1_手写分布式锁错误版本();//模拟两个程序抢占
        b.模拟分布式扣减库存();
        while (Thread.activeCount()>2){//Thread.activeCount() 返回线程总数
            TimeUnit.MICROSECONDS.sleep(50);
        }
        System.out.println("-------------模拟分布式加普通锁模拟------------------------------");
        System.out.println(redis1.get(AMT));
        redis1.close();

    }


    private void 模拟分布式扣减库存() throws InterruptedException {
        ExecutorService threadPool= new ThreadPoolExecutor(10, 10, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000));
        Lock lock = new ReentrantLock();
        for (int i = 0; i < 50; i++) {
            threadPool.execute(()->{
                lock.lock();
                try {
                    Jedis redis = B2_JedisPool.getRedisPool();
                    BigDecimal bigDecimal = new BigDecimal(redis.get(AMT));
                    BigDecimal subtract = bigDecimal.subtract(BigDecimal.valueOf(1));
                    redis.set(AMT,subtract.toString());
                    redis.close();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    lock.unlock();

                }
            });

        }
        threadPool.shutdown();

    }

    @Test//保证 线程安全
    public void 单机加锁() throws InterruptedException {
        ExecutorService threadPool= new ThreadPoolExecutor(100, 100, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000));
        Lock lock = new ReentrantLock();
        System.out.println(Thread.activeCount());//默认有个 main和gc线程
        //连接 redis
        Jedis redis1 = B2_JedisPool.getRedisPool();
        redis1.set(AMT,"100");
        for (int i = 0; i < 100; i++) {
            threadPool.execute(()->{
                lock.lock();
                try {
                    Jedis redis = B2_JedisPool.getRedisPool();

                    //模拟  分布式下的数据更新的   分布式安全
                    BigDecimal bigDecimal = new BigDecimal(redis.get(AMT));
                    BigDecimal subtract = bigDecimal.subtract(BigDecimal.valueOf(1));
                    redis.set(AMT,subtract.toString());

                    redis.close();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    lock.unlock();

                }
            });

        }

        threadPool.shutdown();
        while (Thread.activeCount()>2){//Thread.activeCount() 返回线程总数
            TimeUnit.MICROSECONDS.sleep(50);
//            Thread.yield();
        }//线程个数
        BigDecimal amt1 = new BigDecimal(redis1.get(AMT));
        System.out.println("------------------------");
        System.out.println(amt1);

        //关闭连接
        redis1.close();
    }
    @Test //没保证 线程安全
    public void 单机不加锁() throws InterruptedException {
        ExecutorService threadPool= new ThreadPoolExecutor(100, 100, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000));
        System.out.println(Thread.activeCount());//默认有个 main和gc线程
        //连接 redis
        Jedis redis1 = B2_JedisPool.getRedisPool();
        redis1.set(AMT,"100");
        for (int i = 0; i < 100; i++) {
            threadPool.execute(()->{
                try {
                    Jedis redis = B2_JedisPool.getRedisPool();
                    BigDecimal bigDecimal = new BigDecimal(redis.get(AMT));
                    BigDecimal subtract = bigDecimal.subtract(BigDecimal.valueOf(1));
                    redis.set(AMT,subtract.toString());
                    redis.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            });

        }
        threadPool.shutdown();
        while (Thread.activeCount()>2){//Thread.activeCount() 返回线程总数
            TimeUnit.MICROSECONDS.sleep(50);
        }//线程个数
        BigDecimal amt1 = new BigDecimal(redis1.get(AMT));
        System.out.println("------------------------");
        System.out.println(amt1);


//        TimeUnit.SECONDS.sleep(50);

        //关闭连接
//        redisPool.close();
    }
}
